﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Drawing;

namespace iPhoneUI
{
    [Flags]
    enum DragAxis
    {
        None = 0,
        Horizontal = 1,
        Vertical = 2,
    }

    enum DragDirection
    {
        None,
        Up,
        Down,
        Left,
        Right
    }

    class DragState
    {
        private Point m_start = Point.Empty;
        private Point m_delta = Point.Empty;

        public DragState()
        {
        }

        public bool IsDragging
        {
            get
            {
                return m_start != Point.Empty;
            }
        }

        public Point Delta
        {
            get
            {
                return m_delta;
            }
        }

        public Point DragAxisDelta
        {
            get
            {
                if (IsDraggingHorizontal && Math.Abs(m_delta.X) > StartThreshold)
                    return new Point(m_delta.X, 0);

                if (IsDraggingVertical && Math.Abs(m_delta.Y) > StartThreshold)
                    return new Point(0, m_delta.Y);

                return Point.Empty;
            }
        }

        /// <summary>
        /// The distance neccessary to move before dragging starts
        /// </summary>
        public int StartThreshold { get; set; }

        /// <summary>
        /// The distance necessary before the Direction property indicates
        /// that dragging is significant
        /// </summary>
        public int CommitThreshold { get; set; }

        public bool IsDraggingHorizontal
        {
            get
            {
                return (ContraintAxis & DragAxis.Horizontal) == DragAxis.Horizontal && DragAxis == DragAxis.Horizontal && m_delta.X != 0;
            }
        }

        public bool IsDraggingVertical
        {
            get
            {
                return (ContraintAxis & DragAxis.Vertical) == DragAxis.Vertical && DragAxis == DragAxis.Vertical && m_delta.Y != 0;
            }
        }

        public DragDirection Direction
        {
            get
            {
                if (IsDraggingHorizontal && Math.Abs(m_delta.X) > CommitThreshold)
                {
                    if (m_delta.X > 0)
                        return DragDirection.Right;

                    return DragDirection.Left;
                }

                if (IsDraggingVertical && Math.Abs(m_delta.Y) > CommitThreshold)
                {
                    if (m_delta.Y > 0)
                        return DragDirection.Down;

                    return DragDirection.Up;
                }

                return DragDirection.None;
            }
        }

        public DragAxis ContraintAxis { get; set; }

        public DragAxis DragAxis { get; private set; }

        public void Move(int x, int y)
        {
            m_delta.X = x - m_start.X;
            m_delta.Y = y - m_start.Y;

            if (DragAxis == DragAxis.None)
            {
                int dx = Math.Abs(m_delta.X);
                int dy = Math.Abs(m_delta.Y);

                if (dx > dy)
                    DragAxis = DragAxis.Horizontal;

                if (dy > dx)
                    DragAxis = DragAxis.Vertical;
            }
        }

        public void Start(int x, int y)
        {
            m_start.X = x;
            m_start.Y = y;
            m_delta = Point.Empty;
            DragAxis = DragAxis.None;
        }

        public void Reset()
        {
            m_start = Point.Empty;
            m_delta = Point.Empty;
            DragAxis = DragAxis.None;
        }
    }
}
